#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>

#define BUFSIZE     4096

static void sig_pipe(int sig)
{
    printf("caught SIGPIPE\n");
}

static void parse_message(char *message, int length)
{
    int i, pid, file_fd, write_fd;
    char *filename, clientname[20];
    int have_read;
    char buf[BUFSIZE];
    
    message[length] = '\0';

    printf("receive message: %s\n", message);

    if ((filename = strchr(message, ':')) == NULL)
    {
        printf("message format error\n!");
        exit(0);
    }

    for (i = 0; &message[i] < filename; i ++)
        clientname[i] = message[i];
    clientname[i] = '\0';
    printf("client fifo is %s\n", clientname);

    filename++;
    printf("filename is %s\n", filename);

    file_fd = open(filename, O_RDONLY);
    if (file_fd < 0)
    {
        fprintf(stderr, "open file %s error: %s", 
            filename, strerror(errno));
        exit(0);
    }

    while ((write_fd = open(clientname, O_WRONLY)) < 0)
    {
        if (errno != ENOENT)
        {
            fprintf(stderr, "open file %s error: %s", 
                clientname, strerror(errno));
            exit(0);
        }
    }
    
    while ((have_read = read(file_fd, buf, BUFSIZE)) > 0)
    {
        if (write(write_fd, buf, have_read) < 0)
        {
            perror("write error");
            if (errno == EPIPE)
            {
                printf("unlink %s\n", clientname);
                if (unlink(clientname) < 0)
                    perror("unlink error");
                close(file_fd);
            }
            exit(0);
        }
    }

    if (have_read < 0)
        perror("read error");

    exit(0);
}

int main(int argc, char const* argv[])
{
    int read_fd, write_fd;
    char buf[BUFSIZE];
    int have_read, val;

    read_fd = open("server", O_RDONLY|O_NONBLOCK);
    if (read_fd < 0)
    {
        perror("open for read error");
        exit(0);
    }

    write_fd = open("server", O_WRONLY|O_NONBLOCK);
    if (write_fd < 0)
    {
        perror("open for write error");
        exit(0);
    }

    if (val = (fcntl(read_fd, F_GETFL, 0)) < 0)
    {
        perror("fcntl get_fl error");
        exit(0);
    }

    val &= ~O_NONBLOCK;
    if (fcntl(read_fd, F_SETFL, val) < 0)
    {
        perror("fcntl set_fl error");
        exit(0);
    }

    signal(SIGPIPE, sig_pipe);

    while ((have_read = read(read_fd, buf, BUFSIZE)) > 0)
    {
        if (fork() == 0)
            parse_message(buf, have_read);
    }

    if (have_read <= 0)
        perror("read server fifo error");

    return 0;
}

